package safeCommitter.core.view.main;

import java.util.Collections;

import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Control;

import safeCommitter.core.template.Activator;
import safeCommitter.core.view.main.progress.CounterPanel;
import safeCommitter.core.view.main.progress.JUnitProgressBar;
import safeCommitter.test.executor.common.TestResultType;
import safeCommitter.test.report.ISCTestResult;
import safeCommitter.test.report.RootClazzResult;
import safeCommitter.test.report.SCClazzTestResult;
import safeCommitter.test.report.SCTestResult;

public class SCReportContentProvider implements ITreeContentProvider,
		ISCTestRunListener, IDoubleClickListener, ISelectionChangedListener {

	private TreeViewer viewer;

	private RootClazzResult root;

	private final FailureTraceView failureView;

	private ISCTestResult selectedTest = null;
	private final JUnitProgressBar junitProgressBar;
	private final CounterPanel counterPanel;

	public SCReportContentProvider(final RootClazzResult root,
			final JUnitProgressBar junitProgressBar,
			final CounterPanel counterPanel, final FailureTraceView failureView) {
		Activator.getDefault().addTestListener(this);
		this.root = root;
		this.failureView = failureView;
		this.junitProgressBar = junitProgressBar;
		this.counterPanel = counterPanel;
	}

	public void dispose() {
		Activator.getDefault().removeTestListener(this);
	}

	public void inputChanged(final Viewer viewer, final Object oldInput,
			final Object newInput) {
		this.viewer = (TreeViewer) viewer;
		this.viewer.addDoubleClickListener(this);
		this.viewer.addSelectionChangedListener(this);
	}

	public Object[] getElements(final Object inputElement) {
		return getChildren(inputElement);
	}

	public void testResult(final SCTestResult result) {
		addLastResult(result);
	}

	public void testsFinished() {
	}

	public void testsStarted(final Integer clazzCount, final Integer testCount) {
		Control ctrl = viewer.getControl();
		if (ctrl == null || ctrl.isDisposed())
			return;
		ctrl.getDisplay().syncExec(new Runnable() {
			public void run() {
				junitProgressBar.reset(testCount);
				junitProgressBar.setMaximum(clazzCount, testCount);
				root = new RootClazzResult();
				viewer.setInput(root);
				viewer.refresh();
			}
		});
	}

	public void updateTestCount(final Integer clazzCount,
			final Integer testCount) {
		Control ctrl = viewer.getControl();
		if (ctrl == null || ctrl.isDisposed())
			return;
		ctrl.getDisplay().syncExec(new Runnable() {
			public void run() {
				int clazzMax = junitProgressBar.getMaxTickCount();
				int totalMethodsCounter = junitProgressBar
						.getTotalMethodsCounter();
				junitProgressBar.setMaximum(clazzMax + clazzCount,
						totalMethodsCounter + testCount);
				viewer.refresh();
			}
		});
	}

	private void addLastResult(final SCTestResult result) {
		Control ctrl = viewer.getControl();
		if (ctrl == null || ctrl.isDisposed())
			return;
		ctrl.getDisplay().syncExec(new Runnable() {
			public void run() {
				if (!viewer.getControl().isDisposed())
					viewer.add(result.getParent(), result);
				junitProgressBar.step(result.getStatus());
				viewer.refresh();
			}
		});
	}

	public Object[] getChildren(final Object parentElement) {
		if (parentElement instanceof ISCTestResult
				&& !(parentElement instanceof SCTestResult)) {
			ISCTestResult clazz = (ISCTestResult) parentElement;
			return clazz.getChildren().toArray();
		}
		return Collections.emptyList().toArray();
	}

	public Object getParent(final Object element) {
		if (element instanceof SCTestResult) {
			return ((SCTestResult) element).getParent();
		} else if (element instanceof SCClazzTestResult) {
			return root;
		}
		return null;
	}

	public boolean hasChildren(final Object element) {
		return getChildren(element).length > 0;
	}

	public void addNewClazz(final SCClazzTestResult clazz) {
		root.addChildren(clazz);
		Control ctrl = viewer.getControl();
		if (ctrl == null || ctrl.isDisposed())
			return;
		ctrl.getDisplay().syncExec(new Runnable() {
			public void run() {
				if (!viewer.getControl().isDisposed())
					viewer.add(root, clazz);
				viewer.refresh();
				junitProgressBar.stepTests();
				counterPanel.addResult(clazz.getStatus());
			}
		});
	}

	public void doubleClick(final DoubleClickEvent event) {
		ISCTestResult result = (ISCTestResult) ((TreeSelection) event
				.getSelection()).getFirstElement();
		String path = result.getPath();
		JavaProject javaProject = Activator.getDefault().getJavaProject();
		try {
			ICompilationUnit element = (ICompilationUnit) javaProject
					.findElement(new Path(path + ".class"));
			if (element == null) {
				return;
			}

			SourceType types = (SourceType) element.getTypes()[0];
			if (result instanceof SCTestResult) {
				IMethod method = types.getMethod(((SCTestResult) result)
						.getTestName(), null);
				JavaUI.openInEditor(method);
			}
			JavaUI.openInEditor(element, true, true);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void selectionChanged(final SelectionChangedEvent event) {
		TreeSelection treeSelection = (TreeSelection) event.getSelection();
		selectedTest = (ISCTestResult) treeSelection.getFirstElement();
		if (!(treeSelection.getFirstElement() instanceof SCTestResult)) {
			failureView.clear();
			return;
		}
		SCTestResult result = (SCTestResult) treeSelection.getFirstElement();
		if (result.getStatus().equals(TestResultType.FAILING)) {
			failureView.showFailure(result);
		} else {
			failureView.clear();
		}
	}

	public ISCTestResult getSelectedTest() {
		return selectedTest;
	}

	public void updateStats(final Integer successCount,
			final Integer failCount, final Integer skippCount) {
		Control ctrl = viewer.getControl();
		if (ctrl == null || ctrl.isDisposed())
			return;
		ctrl.getDisplay().syncExec(new Runnable() {
			public void run() {

			}
		});

	}

}
